package com.gylang.auth.controller;

import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.Producer;
import com.gylang.auth.DTO.LoginInfoDTO;
import com.gylang.auth.VO.Result;
import com.gylang.auth.contant.SysConstants;
import com.gylang.auth.domian.SysUser;
import com.gylang.auth.enums.LoginEnum;
import com.gylang.auth.enums.ResultEnum;
import com.gylang.auth.enums.UserEnum;
import com.gylang.common.model.form.LoginForm;
import com.gylang.common.model.form.RePassWdForm;
import com.gylang.common.model.form.RePwMailForm;
import com.gylang.auth.message.LogMessage;
import com.gylang.auth.message.MailMessage;
import com.gylang.auth.security.OnlineUserService;
import com.gylang.auth.service.SysLogService;
import com.gylang.auth.service.SysUserService;
import com.gylang.auth.utils.IPUtils;
import com.gylang.auth.utils.JsonUtils;
import com.gylang.common.utils.Md5Util;
import com.gylang.common.model.log.SysLoginLogMq;
import com.gylang.common.model.mail.MailConstants;
import com.gylang.common.model.mail.TemplateMailBean;
import com.sun.javafx.binding.StringFormatter;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author gylang,
 * @data 2019/11/16 9:32,
 * @DESC
 */
@RestController
@RequestMapping("comm")
public class SysLoginController {

    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private OnlineUserService onlineUserService;
    @Autowired
    private SysLogService logService;
    @Autowired
    private Producer producer;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private MailMessage mailMessage;
    @Autowired
    private LogMessage logMessage;

    @PostMapping("/login")
    public Result login(@RequestBody @Valid LoginForm loginForm, HttpServletRequest request) {
        System.out.println("账号" + JsonUtils.obj2Json(loginForm));
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(loginForm.getUserName(), loginForm.getPassword());
        System.out.println(loginForm);
        subject.login(usernamePasswordToken);
        if (subject.isAuthenticated()) {
            //登录成功 返回token 保存在线列表
            LoginInfoDTO loginInfoDTO = (LoginInfoDTO) subject.getPrincipal();
            String sessionId = SecurityUtils.getSubject().getSession().getId().toString();

            // 将当前登录用户保存到队列当中
            onlineUserService.putAndVerifyUserQueue(loginInfoDTO.getId(), sessionId);
            loginInfoDTO.setToken(sessionId);
            SysLoginLogMq sysLoginLogMq = new SysLoginLogMq();
            sysLoginLogMq.setCreateBy(SysConstants.ADMIN);
            sysLoginLogMq.setIp(IPUtils.getIpAddr(request));
            sysLoginLogMq.setUserName(loginInfoDTO.getName());
            sysLoginLogMq.setStatus("login");
            sysLoginLogMq.setCreateTime(new Date());
            logMessage.sysLoginLog(sysLoginLogMq);
            return Result.success(loginInfoDTO);
        } else {
            return Result.failure(LoginEnum.LOGIN_ERROR);
        }
    }

    @PostMapping("/logout")
    public Result logout(HttpServletRequest request) {

        Subject subject = SecurityUtils.getSubject();
        String sessionId = subject.getSession().getId().toString();
        System.out.println("sessionId :" + sessionId);
        LoginInfoDTO loginInfoDTO = (LoginInfoDTO) subject.getPrincipal();
        if (null == loginInfoDTO) {
//            onlineUserService.removeSession(sessionId);
            return Result.failure(LoginEnum.LOGOUT_ERROR);
        }
        SysLoginLogMq sysLoginLogMq = new SysLoginLogMq();
        sysLoginLogMq.setCreateBy(SysConstants.ADMIN);
        sysLoginLogMq.setIp(IPUtils.getIpAddr(request));
        sysLoginLogMq.setUserName(loginInfoDTO.getName());
        sysLoginLogMq.setStatus("logout");
        sysLoginLogMq.setCreateTime(new Date());
        logMessage.sysLoginLog(sysLoginLogMq);
        subject.logout();
        onlineUserService.removeUserOut(loginInfoDTO.getId(), sessionId);
        return Result.success("注销成功");


    }

    @GetMapping("captcha.jpg")
    public void captcha(HttpServletResponse response, HttpServletRequest request) throws IOException {

        response.setHeader("Cache-Control", "no-store, no-cache");
        System.out.println(request.getRemoteHost() + request.getRemoteAddr() + request.getServletPath());
        String verifyKey = request.getRemoteHost() + Md5Util.generSalt();
        response.setHeader("verifyKey", verifyKey);
        response.setContentType("image/jpeg");
        redisTemplate.opsForValue().set("verifyKey:" +verifyKey, verifyKey, 180, TimeUnit.SECONDS);
        // 生成文字验证码
        String text = producer.createText();
        // 生成图片验证码
        BufferedImage image = producer.createImage(text);
        // 保存到验证码到 session
        request.getSession().setAttribute(Constants.KAPTCHA_SESSION_KEY, text);

        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image, "jpg", out);
        IOUtils.closeQuietly(out);
    }

    @PostMapping("/reset/password")
    public Result findPwByMail(@Valid @RequestBody RePassWdForm rePassWdForm) {

        SysUser sysUser = sysUserService.findByUserName(rePassWdForm.getUsername());
        if (null == sysUser ) {
            return Result.failure(UserEnum.NO_USER);
        }

        String key = StringFormatter.format(SysConstants.MAIL, "resetPw", rePassWdForm.getUsername()).getValue();
        String verifyCode = redisTemplate.opsForValue().get(key);
        System.out.println("验证码" + verifyCode);
        if (rePassWdForm.getCode().equals(verifyCode)) {
            String salt = Md5Util.generSalt();
            sysUser.setPassword(Md5Util.passWdMd5(rePassWdForm.getPassword(), salt));
            sysUser.setSalt(salt);
            sysUserService.save(sysUser);
            redisTemplate.delete(key);
            return Result.success("");
        }
        return Result.failure(ResultEnum.VERIFY_CODE_ERROR);
    }


    @PostMapping("/resetPw/mail")
    public Result resetMail(@Valid @RequestBody RePwMailForm rePwMailForm, HttpServletRequest request) {
        // 校验验证码
               String verifyKey = request.getHeader("verifyKey");
            if (StringUtils.isEmpty(verifyKey) && !rePwMailForm.getCode().equals(redisTemplate.opsForValue().get(verifyKey))) {
                return Result.failure(ResultEnum.VERIFY_CODE_ERROR);
            }
            //校验邮箱格式 true
            SysUser sysUser = sysUserService.findByUserName(rePwMailForm.getUsername());
            if (rePwMailForm.getMail().equals(sysUser.getEmail())) {
                //邮箱-账号匹配 true
                TemplateMailBean mailBean = new TemplateMailBean();
                mailBean.setReceiver(rePwMailForm.getMail());
                mailBean.setSubject("gylang account forgive password");
                mailBean.setSender("862137784@qq.com");
                mailBean.setTemplateName(MailConstants.RSET_PASSWD_MAIL);
                Map<String, Object> params = new HashMap<>();
                params.put("username", rePwMailForm.getUsername());
                String verifyCode = producer.createText();
                params.put("code", verifyCode);
                params.put("deleteEmail", "www.gylang.xyz");
                mailBean.setContent(params);
                mailMessage.sendTemplate(mailBean);
                //缓存code
                String codeKey = StringFormatter.format(SysConstants.MAIL, "resetPw", rePwMailForm.getUsername()).toString();
                redisTemplate.opsForValue().set(codeKey, verifyCode, 300, TimeUnit.SECONDS);

                return Result.success("");

            } else {//邮箱-账号匹配 false
                return Result.failure(UserEnum.NO_USER);
            }
    }
}
